﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Net;
using System.IO;

namespace PickGold
{
	/// <summary/>
	public class SocketReader : TextReader
	{
		private Encoding _Encoding;
		private Socket _Socket;
		private EndPoint _RemotePoint;
		private EndPoint _LastRemote;
		private string _Buffer;
		private Guid[] _History;
		private int _Head;

		/// <summary/>
		public SocketReader(Socket socket, EndPoint remotePoint)
		{
			this._Socket = socket;
			this._RemotePoint = remotePoint;
			this._History = new Guid[byte.MaxValue];
		}

		/// <summary/>
		public Socket Client
		{
			set
			{
				this._Socket = value;
			}
			get
			{
				return this._Socket;
			}
		}

		/// <summary/>
		public EndPoint RemotePoint
		{
			set
			{
				this._RemotePoint = value;
			}
			get
			{
				return this._RemotePoint;
			}
		}

		/// <summary/>
		public EndPoint LastRemote
		{
			get
			{
				return this._LastRemote;
			}
		}

		/// <summary/>
		public Encoding Encoding
		{
			set
			{
				this._Encoding = value;
			}
			get
			{
				if (this._Encoding == null)
					return Encoding.UTF8;

				return this._Encoding;
			}
		}

		/// <summary>
		/// 关闭 System.IO.TextReader 并释放与该 TextReader 关联的所有系统资源。
		/// </summary>
		public override void Close()
		{
			if (this._Socket == null)
				return;

			this._Socket.Close();
		}

		/// <summary>
		/// 释放由 System.IO.TextReader 占用的非托管资源，还可以另外再释放托管资源。
		/// </summary>
		/// <param name="disposing">为 true 则释放托管资源和非托管资源；为 false 则仅释放非托管资源。</param>
		protected override void Dispose(bool disposing)
		{
			if (this._Socket == null)
				return;

			this._Socket.Close();
			this._Socket = null;
		}
		/// <summary>
		/// 读取下一个字符，而不更改读取器状态或字符源。返回下一个可用字符，而实际上并不从输入流中读取此字符。
		/// </summary>
		/// <returns>下一个要读取的字符，或者如果没有更多的可用字符或此流不支持查找，则为 -1。</returns>
		public override int Peek()
		{
			if (this._Socket == null)
				return -1;

			var t = this._Buffer;
			if (t == null)
			{
				if (this.Input() == 0)
					return -1;

				t = this._Buffer;
			}
			if (string.IsNullOrEmpty(t))
				return -1;

			return (int)t[0];
		}
		/// <summary>
		/// 读取输入流中的下一个字符并使该字符的位置提升一个字符。
		/// </summary>
		/// <returns>输入流中的下一个字符，或者如果没有更多的可用字符，则为 -1。默认实现将返回 -1。</returns>
		public override int Read()
		{
			if (this._Socket == null)
				return -1;

			var t = this._Buffer;
			if (t == null)
			{
				if (this.Input() == 0)
					return -1;

				t = this._Buffer;
			}
			if (string.IsNullOrEmpty(t))
				return -1;

			return (int)t[0];
		}
		/// <summary>
		/// 从当前流中读取最大 count 的字符并从 index 开始将该数据写入 buffer。
		/// </summary>
		/// <param name="buffer">此方法返回时，包含指定的字符数组，该数组的 index 和 (index + count - 1) 之间的值由从当前源中读取的字符替换。</param>
		/// <param name="index">buffer 中开始写入的位置。</param>
		/// <param name="count">最多读取的字符数。如果在将 count 个字符读入 buffer 之前已到达流的末尾，则当前方法将返回。</param>
		/// <returns>已读取的字符数。该数小于或等于 count，具体取决于流中是否有可用的数据。如果调用此方法时没有更多的字符留下可供读取，则此方法返回 0。</returns>
		public override int Read(char[] buffer, int index, int count)
		{
			if (this._Socket == null)
				return -1;

			var t = this._Buffer;
			if (t == null)
			{
				if (this.Input() == 0)
					return -1;

				t = this._Buffer;
			}
			if (string.IsNullOrEmpty(t))
			{
				this._Buffer = null;
				if (t == null)
					return -1;

				return 0;
			}

			for (var i = 0; i < count && i < t.Length; i++)
				buffer[i + index] = t[i];
			if (count >= t.Length)
				this._Buffer = null;
			else
				this._Buffer = this._Buffer.Substring(count);
			if (count >= t.Length)
				return count;

			return t.Length;
		}
		/// <summary>
		/// 从当前流中读取最大 count 的字符并从 index 开始将该数据写入 buffer。
		/// </summary>
		/// <param name="buffer">此方法返回时，此参数包含指定的字符数组，该数组中从 index 到 (index + count -1) 之间的值由从当前源中读取的字符替换。</param>
		/// <param name="index">buffer 中开始写入的位置。</param>
		/// <param name="count">最多读取的字符数。</param>
		/// <returns>已读取的字符数。该数字将小于或等于 count，具体取决于是否所有的输入字符都已读取。</returns>
		public override int ReadBlock(char[] buffer, int index, int count)
		{
			return this.Read(buffer, index, count);
		}
		/// <summary>
		/// 从当前流中读取一行字符并将数据作为字符串返回。
		/// </summary>
		/// <returns>输入流的下一行，或者如果已读取了所有字符，则为 null。</returns>
		public override string ReadLine()
		{
			if (this._Socket == null)
				return null;

			var t = this._Buffer;
			if (t == null)
			{
				if (this.Input() == 0)
					return null;

				t = this._Buffer;
			}
			this._Buffer = null;
			if (string.IsNullOrEmpty(t))
				return t;

			var ts = t.Split(Environment.NewLine.ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
			if (ts == null || ts.Length == 0)
				return t;

			return ts[0];
		}
		/// <summary>
		/// 读取从当前位置到 TextReader 的结尾的所有字符并将它们作为一个字符串返回。
		/// </summary>
		/// <returns>包含从当前位置到 TextReader 的结尾的所有字符的字符串。</returns>
		public override string ReadToEnd()
		{
			throw new NotSupportedException();
		}

		private int Input()
		{
			var ep = this._RemotePoint;
			if (ep == null)
			{
				if (this._Socket.AddressFamily == AddressFamily.InterNetwork)
					ep = new IPEndPoint(IPAddress.Any, 0);
				else
					ep = new IPEndPoint(IPAddress.IPv6Any, 0);
			}
			var size = this._Socket.ReceiveBufferSize;
			var bs = new byte[size];
			lock (this._Socket)
			{
				for (; ; )
				{
					if (this._Socket.ProtocolType == ProtocolType.Udp || this._RemotePoint != null)
						size = this._Socket.ReceiveFrom(bs, ref ep);
					else
						size = this._Socket.Receive(bs);
					if (size > BitUtil.SIZE_GUID + BitUtil.SIZE_B64)
					{
						var guid = new Guid(new byte[] { bs[0], bs[1], bs[2], bs[3], bs[4], bs[5], bs[6], bs[7] });
						foreach (var item in this._History)
						{
							if (item == guid)
							{
								size = int.MinValue;
								break;
							}
						}
						if (size >= 0)
						{
							this._Head = (this._Head + 1) % this._History.Length;
							this._History[this._Head] = guid;
							break;
						}
					}
				}
				if (size == BitUtil.SIZE_GUID + BitUtil.SIZE_B64)
					this._Buffer = string.Empty;
				else
					this._Buffer = this.Encoding.GetString(bs, BitUtil.SIZE_GUID + BitUtil.SIZE_B64, size);
				if(this._Buffer != null)
				this._LastRemote = ep;
			}

			return size;
		}
	}
}
